import 'dart:convert';

import 'package:casdon/core/network/business_exception.dart';
import 'package:casdon/core/network/i_api_client.dart';
import 'package:dio/dio.dart';
import 'exception_handler.dart';
import 'base_response.dart';

class DioApiClient extends IApiClient {
  final Dio _dio;
  DioApiClient(this._dio);

  /// 替换路径中的占位符 {param}
  String _replacePathParams(String path, Map<String, dynamic> params) {
    return path.replaceAllMapped(
      RegExp(r'\{(\w+)\}'),
      (match) => params[match.group(1)]?.toString() ?? '',
    );
  }

  /// 过滤掉值为 null 的 query parameters
  Map<String, dynamic>? _filterNullQueryParams(Map<String, dynamic>? query) {
    if (query == null) return null;
    return Map<String, dynamic>.fromEntries(
      query.entries.where((entry) => entry.value != null),
    );
  }

  /// 过滤掉值为 null 的 body/data parameters（仅当 data 是 Map 时）
  dynamic _filterNullBodyParams(dynamic data) {
    if (data is Map<String, dynamic>) {
      return Map<String, dynamic>.fromEntries(
        data.entries.where((entry) => entry.value != null),
      );
    }
    return data;
  }

  /// 通用 GET 请求
  @override
  Future<T?> get<T>(
    String path, {
    Map<String, dynamic>? pathParams,
    Map<String, dynamic>? query,
    Map<String, dynamic>? headers,
  }) async {
    try {
      if (pathParams != null) {
        path = _replacePathParams(path, pathParams);
      }

      final options = Options(headers: headers);
      final res = await _dio.get(
        path,
        queryParameters: _filterNullQueryParams(query),
        options: options,
      );
      return res.data;
    } catch (e, st) {
      final ret = await ExceptionHandler.handle(e);
      if (ret) rethrow;
      return null;
    }
  }

  @override
  Future<BaseResponse<T>?> getTyped<T>(
    String path, {
    Map<String, dynamic>? pathParams,
    Map<String, dynamic>? query,
    bool encrypt = false,
    Map<String, dynamic>? headers,
    required T Function(Object? json) fromJsonT,
  }) async {
    try {
      if (pathParams != null) {
        path = _replacePathParams(path, pathParams);
      }

      final options = Options(headers: headers);
      final res = await _dio.get(
        path,
        queryParameters: _filterNullQueryParams(query),
        options: options,
      );
      var result = await _processResponse(res);
      return BaseResponse<T>.fromJson(result, fromJsonT);
    } catch (e, st) {
      final ret = await ExceptionHandler.handle(e);
      if (ret) rethrow;
      return null;
    }
  }

  @override
  Future<T?> getTypedNOBase<T>(
    String path, {
    Map<String, dynamic>? pathParams,
    Map<String, dynamic>? query,
    bool encrypt = false,
    Map<String, dynamic>? headers,
    required T Function(Object? json) fromJsonT,
  }) async {
    try {
      if (pathParams != null) {
        path = _replacePathParams(path, pathParams);
      }

      final options = Options(headers: headers);
      final res = await _dio.get(
        path,
        queryParameters: _filterNullQueryParams(query),
        options: options,
      );
      var result = await _processResponse(res);
      if (result is Map<String, dynamic>) {
        return fromJsonT(result);
      } else {
        return result as T;
      }
    } catch (e, st) {
      final ret = await ExceptionHandler.handle(e);
      if (ret) rethrow;
      return null;
    }
  }

  /// 通用 POST 请求
  @override
  Future<T?> post<T>(
    String path, {
    Map<String, dynamic>? pathParams,
    dynamic data,
    bool encrypt = false,
    Map<String, dynamic>? headers,
  }) async {
    try {
      if (pathParams != null) {
        path = _replacePathParams(path, pathParams);
      }

      final options = Options(headers: headers, extra: {'encrypt': encrypt});
      final res = await _dio.post(
        path,
        data: _filterNullBodyParams(data),
        options: options,
      );
      return await _processResponse(res);
    } catch (e, st) {
      final ret = await ExceptionHandler.handle(e);
      if (ret) rethrow;
      return null;
    }
  }

  /// 类型化 POST 请求
  @override
  Future<BaseResponse<T>?> postTyped<T>(
    String path, {
    Map<String, dynamic>? pathParams,
    dynamic data,
    bool encrypt = false,
    Map<String, dynamic>? headers,
    required T Function(Object? json) fromJsonT,
  }) async {
    try {
      if (pathParams != null) {
        path = _replacePathParams(path, pathParams);
      }

      final options = Options(headers: headers, extra: {'encrypt': encrypt});
      final res = await _dio.post(
        path,
        data: _filterNullBodyParams(data),
        options: options,
      );
      var result = await _processResponse(res);
      return BaseResponse<T>.fromJson(result, fromJsonT);
    } catch (e, st) {
      final ret = await ExceptionHandler.handle(e);
      if (ret) rethrow;
      return null;
    }
  }

  /// 更新全局headers
  void updateGlobalHeaders(Map<String, dynamic> headers) {
    _dio.options.headers.addAll(headers);
  }

  /// 移除特定header
  void removeGlobalHeader(String key) {
    _dio.options.headers.remove(key);
  }

  /// 添加拦截器
  void addInterceptor(Interceptor interceptor) {
    _dio.interceptors.add(interceptor);
  }

  /// 检查是否业务错误
  Future<void> _checkBusinessError(Response response) async {
    if (response.data is Map) {
      final resp = response.data as Map;
      if ((resp.containsKey('code') &&
              resp['code'] != 200 &&
              resp['code'] != "ok") ||
          (resp.containsKey('ErrorCode') && resp['ErrorCode'] != 0)) {
        throw BusinessException(
          code: resp['code'].toString(),
          msg: resp['msg']?.toString() ?? resp['Message']?.toString() ?? "业务错误",
          data: resp['data'],
        );
      }
    }
    // 当401时，类型为String，目前没看出来是为什么，
    else if (response.data is String) {
      try {
        Map<String, dynamic> jsonMap = jsonDecode(response.data);
        if (jsonMap.containsKey('code') && jsonMap['code'] == 401) {
          throw BusinessException(
            code: jsonMap['code'].toString(),
            msg: jsonMap['msg']?.toString() ?? '业务错误',
          );
        }
      } catch (e) {
        rethrow;
      }
    }
  }

  Future<dynamic> _processResponse(Response res) async {
    try {
      await _checkBusinessError(res); // 只负责校验，不返回数据
    } catch (e) {
      rethrow;
    }

    return res.data; // 这是最终的业务数据
  }

  @override
  Future<T?> delete<T>(
    String path, {
    Map<String, dynamic>? pathParams,
    Map<String, dynamic>? query,
    Map<String, dynamic>? headers,
  }) async {
    try {
      // 替换路径参数（如 /users/{id}）
      if (pathParams != null) {
        path = _replacePathParams(path, pathParams);
      }

      final options = Options(headers: headers);
      final res = await _dio.delete(
        path,
        queryParameters: _filterNullQueryParams(query),
        options: options,
      );

      return await _processResponse(res);
    } catch (e) {
      final ret = ExceptionHandler.handle(e);
      if (ret) rethrow;
      return null;
    }
  }

  @override
  Future<BaseResponse<T>?> deleteTyped<T>(
    String path, {
    Map<String, dynamic>? pathParams,
    Map<String, dynamic>? query,
    Map<String, dynamic>? headers,
    required T Function(Object? json) fromJsonT,
  }) async {
    try {
      // 替换路径参数
      if (pathParams != null) {
        path = _replacePathParams(path, pathParams);
      }

      final options = Options(headers: headers);

      final res = await _dio.delete(
        path,
        queryParameters: _filterNullQueryParams(query),
        options: options,
      );

      final result = await _processResponse(res);
      return BaseResponse<T>.fromJson(result, fromJsonT);
    } catch (e) {
      final ret = ExceptionHandler.handle(e);
      if (ret) rethrow;
      return null;
    }
  }

  @override
  Future<T?> put<T>(
    String path, {
    Map<String, dynamic>? pathParams,
    data,
    Map<String, dynamic>? headers,
  }) async {
    try {
      if (pathParams != null) {
        path = _replacePathParams(path, pathParams);
      }

      final options = Options(headers: headers);

      final res = await _dio.put(
        path,
        data: _filterNullBodyParams(data),
        options: options,
      );

      return await _processResponse(res);
    } catch (e) {
      final ret = ExceptionHandler.handle(e);
      if (ret) rethrow;
      return null;
    }
  }

  @override
  Future<BaseResponse<T>?> putTyped<T>(
    String path, {
    Map<String, dynamic>? pathParams,
    dynamic data,

    Map<String, dynamic>? headers,
    required T Function(Object? json) fromJsonT,
  }) async {
    try {
      if (pathParams != null) {
        path = _replacePathParams(path, pathParams);
      }

      final options = Options(headers: headers);

      final requestData = _filterNullBodyParams(data);

      final res = await _dio.put(path, data: requestData, options: options);

      final result = await _processResponse(res);
      return BaseResponse<T>.fromJson(result, fromJsonT);
    } catch (e) {
      final ret = ExceptionHandler.handle(e);
      if (ret) rethrow;
      return null;
    }
  }

  @override
  Future<void> sse(
    String path, {
    Map<String, dynamic>? pathParams,
    Map<String, dynamic>? query,
    Map<String, dynamic>? headers,
    required void Function(String data) onMessage,
    required void Function(Exception e) onError,
    required void Function() onDone,
    required void Function() onConnectSuccess, // 新增连接成功回调
  }) async {
    bool isConnected = false; // 添加标志来检查是否已经连接成功

    try {
      if (pathParams != null) {
        path = _replacePathParams(path, pathParams);
      }

      final options = Options(
        headers: headers,
        responseType: ResponseType.stream,
      );

      // Perform the GET request for SSE (EventSource)
      final res = await _dio.get<ResponseBody>(
        path,
        queryParameters: _filterNullQueryParams(query),
        options: options,
        onReceiveProgress: (received, total) {}, // Optional progress callback
      );

      // Listening to the stream of server-sent events
      res.data!.stream.listen(
        (data) {
          // Convert the received data (UTF8) to string
          String message = utf8.decode(data);

          // If connection is successful, call the success callback
          if (!isConnected) {
            isConnected = true; // Set the flag to true to avoid multiple calls
            onConnectSuccess(); // Call the connection success callback
          }

          // Process the SSE message
          onMessage(message);
        },
        onError: (error) {
          // Handle the error
          onError(error as Exception);
        },
        onDone: () {
          // Handle when the stream is closed
          onDone();
        },
        cancelOnError: true,
      );
    } catch (e) {
      ExceptionHandler.handle(e);
      onError(e as Exception);
    }
  }
}
